package it.free.maya;

import java.util.List;

import org.apache.log4j.Logger;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocumentList;

/**
 * Class hiding all queries complexities. Entry point to execute queries against the search engine
 * @author Stefano Falconetti
 */
public class SearchEngineQueryProxy {

	private int queryTimeout = 0;
	private String localServer = null;
	
	private static SearchEngineQueryProxy SEARCH_ENGINE_QUERY_PROXY_INSTANCE = null;
	private static Logger logger = Logger.getLogger(SearchEngineQueryProxy.class);
	
	private static final String SOLR_SHARD_QUERY_TIMEOUT = "solr.shards.query.timeout";
	private static final String SOLR_SHARD_LOCAL_SERVER = "solr.shards.local.server";

	/**
	 * Made private as this is a singleton
	 */
	private SearchEngineQueryProxy(){
		
		//First activate loading of all shards configurations if present
		SolrShardsRegistrySingletonImpl.getInstance();
		 
		
//		if( (SolrShardsRegistrySingletonImpl.getInstance().isConfigured()) &&
//			 SolrShardsRegistrySingletonImpl.getInstance().getSize() != 0){
//		
//			Runnable solrShardsCheckingDaemon = new SolrShardsHealthCheckingDaemon();
//			Thread solrShardsCheckingDaemonThread = new Thread(solrShardsCheckingDaemon, 
//			 											      ("Shards-ping-thread-" + SolrShardsHealthCheckingDaemon.class.getSimpleName()));
//			solrShardsCheckingDaemonThread.start();
//		}else{
//			  logger.info("No shard configured, ping daemon not activated");
//		}
		
		this.queryTimeout = Integer.parseInt(SolrShardsPropertiesLoader.getProperty(SearchEngineQueryProxy.SOLR_SHARD_QUERY_TIMEOUT));
		this.localServer = SolrShardsPropertiesLoader.getProperty(SearchEngineQueryProxy.SOLR_SHARD_LOCAL_SERVER);
	}
	
	/**
	 * Singleton accessor to this object instance
	 * @return the singleton instance
	 */
	public synchronized static final SearchEngineQueryProxy getInstance(){
		
		if(SearchEngineQueryProxy.SEARCH_ENGINE_QUERY_PROXY_INSTANCE == null){
		   SearchEngineQueryProxy.SEARCH_ENGINE_QUERY_PROXY_INSTANCE = new SearchEngineQueryProxy();
		}
		
		return SearchEngineQueryProxy.SEARCH_ENGINE_QUERY_PROXY_INSTANCE;
	}
	
	/**
	 * Execute a use query
	 * @param query is the query to execute
	 * @param starFromRow firt row to be retrieved
	 * @param maxRows max number of rows tp get in the result
	 * @param sortDescendingByField field to use in descending sort
	 * @return the result of the queries
	 * @throws Exception
	 * @Deprecated use other overload of this one
	 */
	public SolrDocumentList executeQuery(String query, 
										 int starFromRow, 
										 int maxRows, 
										 String sortDescendingByField) throws Exception {
		
		SolrDocumentList solrDocumentList = null;
		
		if( (query == null) || 
			(query.trim().equals(""))){
		   logger.error("No query, cannot execute");
		   return solrDocumentList;
		}
		
		SolrQuery solrQuery = new SolrQuery();
		
		CommonsHttpSolrServer commonsHttpSolrServerForQueries = buildSolrServer(solrQuery);
		
		solrQuery.setQuery(query);
				
		solrQuery.setStart(starFromRow);
		solrQuery.setRows(maxRows);
		solrQuery.addSortField(sortDescendingByField, SolrQuery.ORDER.desc);
		
		QueryResponse queryResponse = commonsHttpSolrServerForQueries.query(solrQuery);
		solrDocumentList = queryResponse.getResults();
		
		return solrDocumentList;
	}
	
	/**
	 * Execute a use query
	 * @param query is the query to execute
	 * @param starFromRow first row to be retrieved
	 * @param maxRows max number of rows to get in the result, paging. Keep this low.
	 * @param sortDescendingByField field to use in descending sort
	 * @param orderDrection is the sorting order
	 * @param activateFacet enable faceted query
	 * @param facetField is the field to execute facet query on
	 * @return the result of the queries
	 * @throws Exception
	 */
	public FacetedSearchResult executeQuery(String query, 
										    int starFromRow, 
										    int maxRows, 
										    String sortDescendingByField,
										    SolrQuery.ORDER orderDrection,
										    boolean activateFacet,
										    String facetField) throws Exception {
		
		FacetedSearchResult facetedSearchResult = FacetedSearchResult.createInstance();
		
		if( (query == null) || 
			(query.trim().equals(""))){
		   logger.error("No query, cannot execute");
		   return facetedSearchResult;
		}
		
		SolrDocumentList solrDocumentList = null;
		List<FacetField> facetFields = null;
		
		SolrQuery solrQuery = new SolrQuery();
		
		CommonsHttpSolrServer commonsHttpSolrServerForQueries = buildSolrServer(solrQuery);
		
		solrQuery.setQuery(query);
				
		solrQuery.setStart(starFromRow);
		solrQuery.setRows(maxRows);
		solrQuery.addSortField(sortDescendingByField, orderDrection);
		
		if(activateFacet){
		   solrQuery.setFacet(activateFacet);
		   //"category_description"
		   solrQuery.addFacetField(facetField);
		}
		
		QueryResponse queryResponse = commonsHttpSolrServerForQueries.query(solrQuery);
		facetFields = queryResponse.getFacetFields();
		solrDocumentList = queryResponse.getResults();
		
		facetedSearchResult.setFacetFields(facetFields);
		facetedSearchResult.setSolrDocumentList(solrDocumentList);
		
		/* For Gianluca: this is the loop to read facet query results, 
		Iterator<FacetField> facetFieldIterator = facetFields.iterator();
		
		FacetField aFacetField = null;
		
		List<Count> counts = null;
		Iterator<Count> countIterator = null;
		Count aCount = null;
		
		while(facetFieldIterator.hasNext()){
			  aFacetField = facetFieldIterator.next();
			  counts = aFacetField.getValues();
			  countIterator = counts.iterator();
			  while(countIterator.hasNext()){
				    aCount = countIterator.next();
			        System.out.println("Category: [" + aCount.getName() + "] count: [" + aCount.getCount() + "]");
			  }
	    }
		*/
		
		return facetedSearchResult;
	}
	
	/**
	 * Build the sold server connection according to possible shards configurations
	 * @param aSolrQuery is the query passed to be set for non user generated parameters 
	 * @return a connection object to the index server
	 */
	private final CommonsHttpSolrServer buildSolrServer(SolrQuery aSolrQuery) throws Exception{

		CommonsHttpSolrServer commonsHttpSolrServerForQueries = new CommonsHttpSolrServer(this.localServer);
				
		commonsHttpSolrServerForQueries.getHttpClient().getParams().setSoTimeout(this.queryTimeout);
		commonsHttpSolrServerForQueries.setConnectionTimeout(this.queryTimeout);
		commonsHttpSolrServerForQueries.setDefaultMaxConnectionsPerHost(1);
		commonsHttpSolrServerForQueries.setMaxTotalConnections(1);
		commonsHttpSolrServerForQueries.setMaxRetries(1); // defaults to 0.  > 1 not recommended.
		commonsHttpSolrServerForQueries.getHttpClient().getParams().setContentCharset("UTF-8");
		
		return commonsHttpSolrServerForQueries;
		
	}
}
